home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 7 / BBS in a Box - Macintosh - Volume VII (BBS in a Box) (January 1993).iso / Files / Tele / C / Comet2.1.3.cpt / Comet / 3270com.c < prev    next >
Text File  |  1991-08-22  |  29KB  |  1,237 lines

  1. /*
  2.  * COPYRIGHT 1987 CORNELL UNIVERSITY; All Rights Reserved
  3.  *  Please see detailed copyrights and disclaimers in "notices.h"
  4.  */
  5.  
  6. /***************************************************************************
  7. *     This is the 3270 datastream command processor. It is passed a pointer *
  8. *     to a string containing one 3270 command and associated orders and/or  *
  9. *     data and the length of the string to process.                                 *
  10. *     written by Peter Hoyt, Cornell Computer Services
  11. *        and bloody well extensively modified by kevin eric saunders!
  12. ***************************************************************************/
  13.  
  14. #include <em.h>
  15. #include <3270.h>
  16.  
  17. #ifdef USEMACTCP
  18. #include "mactcp.h"
  19. #endif
  20.  
  21.  
  22. /* the possible emulator states ... */
  23.  
  24. #define CMNORM        0
  25. #define CMCONT        1
  26. #define CMWRITE        2
  27. #define CMWRITE1    3
  28. #define CMEAT        4
  29. #define CMEAT1        5
  30. #define CMSBA        6
  31. #define CMSBA1        7
  32. #define CMRA        8
  33. #define CMRA1        9
  34. #define CMRA2        10
  35. #define CMEUA        11
  36. #define CMEUA1        12
  37. #define CMSF        13
  38.  
  39.  
  40. char commandmap[256];            /* map of write orders to avoid switch overhead */
  41.  
  42. cmd(ptr, length)
  43. register unsigned char *ptr;
  44. register int  length;
  45. {
  46.     register unsigned char * curptr;
  47.     register unsigned char * mapend = smap_end;
  48.     register unsigned char thechar;            /* current data/command byte */
  49.     register short haddata;                /* the last byte processed was data */
  50.     unsigned char * attp;
  51.     unsigned char achar;
  52.     short acount;
  53.     short cnt;
  54.     struct token * tkptr;
  55.  
  56.     if (length == 0)
  57.         return(0);
  58.         
  59.     if (cmdstate) {
  60.         /* we were in the middle of handling a 3270 command string;
  61.             resume where we left off.  curptr & emdp->savcount states must 
  62.             be maintained */
  63.         curptr = emdp->savcurptr;
  64.         haddata = emdp->savdata;
  65.         
  66.         if (cmdstate == CMCONT) {
  67.             /* we just needed to restore state before proceeding */
  68.             thechar = *ptr++; 
  69.             --length; 
  70.         }
  71.         else if (cmdstate == CMWRITE1)
  72.             /* predominant case */
  73.             goto CMDWRITE1;
  74.             
  75.         switch (cmdstate) {
  76.             case CMWRITE:
  77.                 goto CMDWRITE;
  78.             case CMSF:
  79.                 goto CMDSF;
  80.             case CMSBA:
  81.                 goto CMDSBA;
  82.             case CMSBA1:
  83.                 goto CMDSBA1;
  84.             case CMRA:
  85.                 goto CMDRA;
  86.             case CMRA1:
  87.                 goto CMDRA1;
  88.             case CMRA2:
  89.                 goto CMDRA2;
  90.             case CMEAT:
  91.                 goto CMDEAT;
  92.             case CMEAT1:
  93.                 goto CMDEAT1;
  94.             case CMEUA:
  95.                 goto CMDEUA;
  96.             case CMEUA1:
  97.                 goto CMDEUA1;
  98.         }
  99.     }
  100.     else {
  101.         cmdstate = CMCONT;
  102.         thechar = *ptr++; 
  103.         --length; 
  104.     }
  105.  
  106.     switch (thechar) {
  107.         case EW:
  108.           /* erase / write command */
  109.         case EWA: {
  110.             /* erase / write alternate */
  111.             /* reset the screen buffer & reposition cursor
  112.                 if most recent action (or cmd) not a CLEAR */
  113.             if (!(emdp->event_reg & CLEAR_KEY)) {
  114.                 modflg = SCRALLMOD;
  115.                 mem_clear(scr_map, emdp->screensize, (char) IBMNULL);
  116.                 cursor_ptr = scr_map;
  117.                 current_attr = NULL;
  118.                 newibmcursor();
  119.             }
  120.         /* these guys fall into normal write */
  121.         /* we may spend a lot of time in here now */
  122.         }
  123.         case W: {
  124.           /* write command */
  125.     /* TODO lookahead crap */
  126.             if (length == 4 && *(ptr + 1) == 0x11)
  127.                 /* check for special case of using a lone SBA */
  128.                 emdp->scr_flag = 1;
  129.             else {
  130.                 /* to establish screen buffer ptr for a read command that  
  131.                     is to follow immediately */
  132.                 emdp->scr_flag = 0;              
  133.                 emdp->scr_org = scr_map;
  134.             }
  135.             /* ignore command if no WCC ? */
  136.             /* kevin TODO should not ignore EAU!  3-2 3270 guide ? */
  137.     
  138. CMDWRITE:
  139.             if (--length < 0) {
  140.                 cmdstate = CMWRITE;
  141.                 goto end_write; 
  142.             }
  143.             thechar = *ptr++;
  144.     
  145.             /* next char has WCC command stuff in it */
  146.             if (thechar & SNDALRM) 
  147.                 emdp->event_reg |= SOUND_ALARM;    
  148.                 /* process WCC */
  149.             if (thechar & KYBDRST) 
  150.                 emdp->event_reg |= KYBD_RESTORE;  
  151.                 /* execute later */
  152.             if ((thechar & RMDT) && current_attr != NULL) {
  153.                 /* reset MDT */
  154.                 attp = current_attr;
  155.                 *attp &= ~MDT;
  156.                 while ((attp = look_attr(attp, FWD)) != current_attr) 
  157.                     *attp &= ~MDT;
  158.             }
  159.     
  160.             curptr = cursor_ptr;
  161.                 /* default */
  162.             haddata = FALSE;
  163.                 /* last char. processed not data */
  164.             firstp = NULL;
  165.             
  166.             length = ft_check(ptr, length);
  167.     /* TODO lookahead crap */
  168.                 /* check for file transfer */
  169.             while (TRUE) {
  170.                 /* process orders & data */
  171. CMDWRITE1:
  172.                 if (--length < 0) {
  173.                     cmdstate = CMWRITE1;
  174.                     goto end_write; 
  175.                 }
  176.                 thechar = *ptr++;
  177.     
  178.                 if (!commandmap[thechar]) {
  179.                     /* normal data for screen display */
  180.                     if (!firstp) 
  181.                         firstp = curptr;
  182.                     thechar = ebctoasc[thechar];
  183.                     *curptr++ = thechar;
  184.                     if (curptr >= mapend) {
  185.                         set_mod(firstp, curptr - firstp);
  186.                         curptr = scr_map;
  187.                         firstp = NULL;
  188.                     }
  189.                     haddata = TRUE;
  190.                     if (emdp->matchinput) {
  191.                         /* we're trying to match input characters */
  192.                         if (matchtoken(thechar))
  193.                             resumetokens(emdp); 
  194.                     }
  195.                     continue;
  196.                         /* for program tab */
  197.                 }
  198.                 else {
  199.                     switch (thechar) {
  200.                         /* check for orders */
  201.                         /* not all orders are supported */
  202.                         case 0x2c:    /* modify field */
  203.                         case 0x29:    /* start field extended */
  204.                         case 0x28:    /* set attribute */
  205.                         {
  206.                             if (thechar != 0x28) { 
  207. CMDEAT:
  208.                                 if (--length < 0) {
  209.                                     cmdstate = CMEAT;
  210.                                     goto end_write; 
  211.                                 }
  212.                                 thechar = *ptr++; 
  213.                             }
  214.                             else 
  215.                                 thechar = 1;
  216.                             for (emdp->savcount = (thechar * 2); emdp->savcount--; ) {
  217.                                 /* eat unwanted type/value pairs */
  218. CMDEAT1:
  219.                                 if (--length < 0) {
  220.                                     cmdstate = CMEAT1;
  221.                                     goto end_write; 
  222.                                 }
  223.                                 thechar = *ptr++; 
  224.                             }
  225.                             haddata = FALSE;
  226.                             break;
  227.                         }
  228.                         case 0x08: {
  229.                           /* graphics escape is ignored */
  230.                             haddata = FALSE;
  231.                             break;
  232.                         }
  233.                         case SF: {
  234.                             /* start field */
  235.                             unsigned char * nfield;
  236.     
  237.                             if (firstp) {
  238.                                 /* do set mod for touched range */
  239.                                 
  240.                                 set_mod(firstp, curptr - firstp);
  241.                                 firstp = NULL;
  242.                             }
  243. CMDSF:
  244.                             if (--length < 0) {
  245.                                 cmdstate = CMSF;
  246.                                 goto end_write; 
  247.                             }
  248.                             thechar = *ptr++; 
  249.     
  250.                             if (thechar & HOSTPROT)
  251.                                 thechar |= PROT;
  252.                             else
  253.                                 thechar &= ~PROT;
  254.  
  255.                             thechar &= 0x1F;
  256.                             /* see if the new field needs to have modflg set on its range */
  257.                             if (modflg < SCRALLMOD) {
  258.                                 nfield = look_attr(curptr, BACK);
  259.                                 if ((*nfield & emdp->realattr) 
  260.                                         != (thechar & emdp->realattr)) {
  261.                                         
  262.                                     nfield = look_attr(curptr, FWD);
  263.                                     if (nfield > curptr) {
  264.                                         acount = nfield - curptr;
  265.                                     }
  266.                                     else {
  267.                                         acount = nfield - scr_map + mapend - curptr;
  268.                                     }
  269.                                     set_mod(curptr, acount);
  270.                                 }
  271.                             }
  272.                             *curptr++ = thechar;    /* mask out irrelevant part */
  273.                             if (curptr >= mapend) 
  274.                                 curptr = scr_map;
  275.  
  276.                             haddata = FALSE;
  277.                             break;
  278.                         }
  279.                         case SBA: {
  280.                             /* set buffer address */
  281.                             if (firstp) {
  282.                                 /* do set mod for touched range */
  283.                                 set_mod(firstp, curptr - firstp);
  284.                                 firstp = NULL;
  285.                             }
  286. CMDSBA:
  287.                             if (--length < 0) {
  288.                                 cmdstate = CMSBA;
  289.                                 goto end_write; 
  290.                             }
  291.                             thechar = *ptr++; 
  292.     
  293.                             emdp->savcount = ((short) (thechar & 0x3f)) * 64;
  294. CMDSBA1:
  295.                             if (--length < 0) {
  296.                                 cmdstate = CMSBA1;
  297.                                 goto end_write; 
  298.                             }
  299.                             thechar = *ptr++;
  300.     
  301.                             emdp->savcount += (short) (thechar & 0x3f);
  302.                             curptr = scr_map + emdp->savcount;
  303.                             while (curptr >= mapend)
  304.                                  curptr -= emdp->screensize;        
  305.                             if (emdp->scr_flag) {
  306.                                 emdp->scr_flag = 0;        /* set special pointer */
  307.                                 emdp->scr_org = curptr;        /* this one time */
  308.                             }
  309.                             haddata = FALSE;
  310.                             break;
  311.                         }
  312.                         case IC: {
  313.                             /* insert cursor */
  314.                             cursor_ptr = curptr;
  315.                             newibmcursor();
  316.                             haddata = FALSE;
  317.                             break;
  318.                         }
  319.                         case RA: {
  320.                             /* repeat to address */
  321.                             if (firstp) {
  322.                                 /* do set mod for touched range */
  323.                                 set_mod(firstp, curptr - firstp);
  324.                                 firstp = NULL;
  325.                             }
  326.                             /* first figure address itself */
  327. CMDRA:
  328.                             if (--length < 0) {
  329.                                 cmdstate = CMRA;
  330.                                 goto end_write; 
  331.                             }
  332.                             thechar = *ptr++;
  333.                             emdp->savcount = ((short) (thechar & 0x3f)) * 64;
  334. CMDRA1:
  335.                             /* then figure distance to it */
  336.                             if (--length < 0) {
  337.                                 cmdstate = CMRA1;
  338.                                 goto end_write; 
  339.                             }
  340.                             thechar = *ptr++;
  341.                             emdp->savcount += (short) (thechar & 0x3f);
  342.     
  343.                             /* get character to repeat */
  344. CMDRA2:
  345.                             if (--length < 0) {
  346.                                 cmdstate = CMRA2;
  347.                                 goto end_write; 
  348.                             }
  349.                             thechar = *ptr++;
  350.  
  351.                                 /* are we ahead of or behind the cursor ? */
  352.                             if (emdp->savcount > emdp->screensize)
  353.                                 /* keep it inside the buffer! */
  354.                                 emdp->savcount = emdp->screensize;
  355.                                 
  356.                             /* translate emdp->savcount from address to counter */
  357.                             if (scr_map + emdp->savcount > curptr) 
  358.                                 emdp->savcount -= curptr - scr_map;
  359.                             else 
  360.                                 emdp->savcount += mapend - curptr;
  361.     
  362.                             if (curptr + emdp->savcount > mapend) {
  363.                                 /* will we wrap? */
  364.                                 cnt = (mapend - curptr);
  365.                                 mem_clear(curptr, cnt, ebctoasc[thechar]);
  366.                                 set_mod(curptr, cnt);
  367.     
  368.                                 mem_clear(scr_map, emdp->savcount - cnt, ebctoasc[thechar]);
  369.                                 set_mod(scr_map, emdp->savcount - cnt);
  370.                             }
  371.                             else {
  372.                                 mem_clear(curptr, emdp->savcount, ebctoasc[thechar]);
  373.                                 set_mod(curptr, emdp->savcount);
  374.                             }
  375.                             curptr += emdp->savcount;
  376.                                 /* fix the buffer pointer */
  377.                             while (curptr >= mapend) 
  378.                                 /* was if */
  379.                                 curptr -= emdp->screensize;
  380.                             haddata = FALSE;
  381.                             break;
  382.                         }
  383.                         case EUA: {
  384.                             /* erase unprotected to address */
  385.                             if (firstp) {
  386.                                 /* do set mod for touched range */
  387.                                 set_mod(firstp, curptr - firstp);
  388.                                 firstp = NULL;
  389.                             }
  390.     /* ugh.. not thoroughly tested */
  391. CMDEUA:
  392.                             if (--length < 0) {
  393.                                 cmdstate = CMEUA;
  394.                                 goto end_write; 
  395.                             }
  396.                             thechar = *ptr++;
  397.                             emdp->savcount = ((short) (thechar & 0x3f)) * 64;
  398. CMDEUA1:
  399.                             if (--length < 0) {
  400.                                 cmdstate = CMEUA1;
  401.                                 goto end_write; 
  402.                             }
  403.                             thechar = *ptr++;
  404.                             emdp->savcount += (short) (thechar & 0x3f);            /* calc. dist. to addr. */
  405.                             if (emdp->savcount > emdp->screensize)
  406.                                 /* keep it inside the buffer! */
  407.                                 emdp->savcount = emdp->screensize;
  408.                                 
  409.                             if (scr_map + emdp->savcount > curptr) 
  410.                                 emdp->savcount -= (curptr - scr_map);
  411.                             else 
  412.                                 emdp->savcount += (mapend - curptr);
  413.                             /* must be formatted buffer */
  414.                             if ((attp = look_attr(curptr, BACK)) != NULL) {
  415.                                 set_mod(curptr, emdp->savcount);
  416.                                 while (emdp->savcount-- > 0) {
  417.                                     /* not attr & unprotected */
  418.     
  419.                                     if (*curptr >= ATTR && !(*attp & PROT)) 
  420.                                         *curptr = IBMNULL;
  421.                                     if (++curptr == mapend) 
  422.                                         curptr = scr_map;
  423.                                     if (*curptr < ATTR) 
  424.                                         attp = curptr;        /* new field */
  425.                                 }
  426.                             }
  427.                             haddata = FALSE;
  428.                             break;
  429.                         }
  430.                         case PT: {
  431.                             /* program tab */
  432.                             if (firstp) {
  433.                                 /* do set mod for touched range */
  434.                                 set_mod(firstp, curptr - firstp);
  435.                                 firstp = NULL;
  436.                             }
  437.                             if (haddata == FALSE) {
  438.                                 curptr = first_unp(curptr);
  439.                                 /* haddata remains false */
  440.                             }
  441.                             else {
  442.                                 while (curptr != mapend && *curptr >= ATTR) {
  443.                                     *curptr = IBMNULL;
  444.                                     set_mod(curptr++, 1);
  445.     /* EFFICIENCY */
  446.                                 }
  447.                                 if (curptr >= mapend) {
  448.                                     /* frought with special cases */
  449.                                     curptr = scr_map;
  450.                                     /* haddata remains true */
  451.                                 }
  452.                                 else {
  453.                                     /* NORMAL CASE? haddata && middle of screen */
  454.                                     /* HOYT: probably dosen't work & never meant to */
  455.                                     curptr = first_unp(curptr);
  456.                                     haddata = FALSE;
  457.                                 }
  458.                             }
  459.                             break;
  460.                         }
  461.                     }
  462.                 }
  463.                 /* end of switch on next order or data */
  464.                 /* we have processed another order or data byte */
  465.             }
  466.             /* end while loop (write command) */
  467.     
  468. end_write:
  469.     /* branch here if orphan order */
  470.     
  471.             if (firstp != NULL) {
  472.                 /* do set mod for touched range */
  473.                 set_mod(firstp, curptr - firstp);
  474.                 firstp = NULL;
  475.             }
  476.             emdp->savcurptr = curptr;
  477.             emdp->savdata = haddata;
  478.             if (emdp->event_reg & TFTP_ON) {
  479.                 /* we've gone into file transfer mode, end of cmd */
  480.                 cmdcomplete();
  481.             }
  482.  
  483.             return(0);
  484.         }
  485.     
  486.     /*  other 3270 commands follow */
  487.     
  488.         case 0x02: {
  489.           /* read buffer */
  490.             read_buf();
  491.             break;
  492.         }
  493.         case 0x06: {
  494.             /* read modified unsolicited by action key */
  495.             /* most read modifies are handled by the telnet
  496.                 server on the host since we pass the results
  497.                 of one every time we send an action key */
  498.             read_mod();
  499.             emdp->scr_org = scr_map;
  500.             break;
  501.         }
  502.         case 0x0f: {
  503.             /* erase all unprotected */
  504.             if (current_attr) {
  505.                 /* do only if formatted buffer */
  506.                 eau();
  507.                     /* manual is unclear on this */
  508.                 emdp->event_reg |= KYBD_RESTORE;
  509.                 emdp->event_reg |= SCREEN_REFRESH;
  510.             }
  511.             emdp->scr_org = scr_map;
  512.             break;
  513.         }
  514.         default: {
  515.             /* something unknown */
  516.             if (!emdp->emdisable)
  517.                 beep();
  518.             break;
  519.         }
  520.     }
  521.  
  522.     return();
  523. }
  524.  
  525.  
  526. /* a 3270 command is complete, indicated by receipt of IAC EOR */
  527.  
  528. cmdcomplete()
  529. {
  530.     cmdstate = CMNORM;
  531.     if (emdp->event_reg & SOUND_ALARM) {
  532.         /* deal with postponed actions */
  533.         if (emdp->ayt_sent == 0 && !emdp->emdisable)
  534.             /* don't beep if this is just a response to an Are You There     */
  535.             beep();
  536.         emdp->ayt_sent = 0;
  537.         emdp->event_reg &= ~SOUND_ALARM;
  538.     }
  539.     if (emdp->event_reg & KYBD_RESTORE) {
  540.         emdp->event_reg &= ~KYBD_RESTORE;
  541.         if (emdp->event_reg & KYBD_LOCK) {
  542.             clrkbdlock();
  543.             emdp->event_reg &= ~KYBD_LOCK;
  544.         }
  545.         if (emdp->event_reg & SYS_LOCK) {
  546.             clrsyslock();
  547.             emdp->event_reg &= ~SYS_LOCK;
  548.         }
  549.         emdp->aid_key =  AID_RESET;
  550.     }
  551.     emdp->event_reg |= SCREEN_EVENT;
  552.     emdp->event_reg &= ~CLEAR_KEY;
  553.         /* most recent action no longer CLEAR */
  554.  
  555.     if (*cursor_ptr < ATTR)            /* reposition current attr pointer */
  556.         current_attr = cursor_ptr;
  557.     else 
  558.         current_attr = look_attr(cursor_ptr, BACK);
  559. }
  560.  
  561.  
  562. /* send the current buffer to the host 
  563.     Note if using only MacTCP, TC_PUT macro can be used */
  564.  
  565. read_buf()
  566. {
  567.     register unsigned char * curptr;
  568.     register unsigned char * mapend = smap_end;
  569.     register unsigned char achar;
  570.     register short acount;
  571.  
  572.     (*emdp->putchar)(emdp->aid_key);
  573.         /* return AID & cursor address */
  574.     acount = addr_12 (cursor_ptr - scr_map);
  575.     (*emdp->putchar)(acount >> 8);
  576.     (*emdp->putchar)(acount & 0xff);
  577.  
  578.     for (curptr = emdp->scr_org; curptr < mapend; ) {
  579.         if ((achar = *curptr++) >= ATTR) {
  580.             /* send data */
  581.             (*emdp->putchar)(asctoebc[achar]);
  582.         }
  583.         else { 
  584.             /* if new field (because of attr) */
  585.             (*emdp->putchar)(0x1d);  
  586.                 /* send SF order + attr */
  587.             if (achar & PROT) {
  588.                 /* put the protected bit in the right place */
  589.                 achar &= ~PROT;
  590.                 achar |= HOSTPROT;
  591.             }
  592.             achar = achar & 0x3f;
  593.             achar |= 0x40;
  594.             if ((achar & 0x0f) <= 9) {
  595.                 if ((achar & 0x30) == 0x30 
  596.                         || (achar & 0x0f) > 2 
  597.                         || achar == 0x41 
  598.                         || achar == 0x51
  599.                     ) 
  600.                     achar |= 0x80;
  601.             }
  602.             (*emdp->putchar)(achar);
  603.         }
  604.     }
  605.     /* don't forget telnet command */
  606.     (*emdp->putchar)(0xff);
  607.     (*emdp->putchar)(0xef);
  608.     (*emdp->putflush)();
  609.     
  610.     emdp->scr_org = scr_map;
  611. }
  612.  
  613.  
  614. /*  Read modify logic used by both command processor & keyboard routine.
  615. **    In a real 3270 the host always issues a read modify and the terminal
  616. **    sends the most recent AID, cursor addr, & any fields with MDT set. In
  617. **    our telnet application, we perform the read modified and send the data
  618. **    when the user presses ENTER or a PF key, and the telnet server uses the
  619. **    data when the host application issues the read modified. In addition the
  620. **    local PC application must provide for the host issuing a read modified
  621. **    at any time. Ergo rather than duplicate code we made this subroutine. 
  622. */
  623.  
  624. read_mod() 
  625. {
  626.     register unsigned char * ptr;
  627.     register unsigned char * mapend = smap_end;
  628.     register unsigned char * nullp;
  629.     unsigned char * endp;
  630.     unsigned char * nextattp;
  631.  
  632.     register unsigned short thechar;
  633.     register short fieldcount;
  634.     short count;
  635.     unsigned char aid = emdp->aid_key;
  636.     
  637.     (*emdp->putchar)(aid);
  638.     /* send AID & cursor addr */
  639.     if (! ((aid == RPA1) 
  640.             || (aid == RPA2) 
  641.             || (aid == RPA3) 
  642.             || (aid == RCLEAR) )) {
  643.  
  644.         /* PA keys and CLEAR produce only AID, no data */
  645.         count = addr_12(cursor_ptr - scr_map);
  646.         (*emdp->putchar)(count >> 8);
  647.         (*emdp->putchar)(count & 0xff);
  648.         if (emdp->scr_org == scr_map)        
  649.             /* so as not to miss a field that */
  650.             /* starts at upper left */
  651.             ptr = look_attr(scr_map + emdp->screensize - 1, FWD);  
  652.         else
  653.             /* special case SBA + nothing */
  654.             ptr = look_attr(emdp->scr_org, FWD);
  655.  
  656.         if (ptr == NULL) {
  657.             /* unformatted buffer */
  658.             for (ptr = emdp->scr_org; ptr < mapend; ) {
  659.                 if ((thechar = *ptr++) != IBMNULL) {
  660.                     /* translate character */
  661.                     (*emdp->putchar)(asctoebc[thechar]);
  662.                 }
  663.             }
  664.         }
  665.         else {
  666.             endp = ptr;
  667.             do {
  668.                 if (*ptr & MDT) {
  669.                     /* if MDT for this field, field modified */
  670.                     nullp = nextattp = look_attr(ptr, FWD);
  671.                     if (ptr < nextattp)
  672.                         /* "normal" case */
  673.                         fieldcount = (nullp - ptr);
  674.                     else
  675.                         /* we've wrapped */
  676.                         fieldcount = (nullp - scr_map) + (smap_end - ptr);
  677.                     /* note that fieldcount is 1 high for predecrement */
  678.  
  679.                     if (++ptr == mapend) 
  680.                         ptr = scr_map;
  681.                     (*emdp->putchar)(0x11);
  682.                         /* SBA order */
  683.                     count = addr_12(ptr - scr_map);
  684.                     (*emdp->putchar)(count >> 8);
  685.                     (*emdp->putchar)(count & 0xff);
  686.                     if (fieldcount) {
  687.                         /* adjust end so consecutive nulls won't be sent */
  688.                         if (nullp <= scr_map)
  689.                             nullp += emdp->screensize;
  690.  
  691.                         while (--fieldcount && *--nullp == IBMNULL ) {
  692.                             if (nullp <= scr_map)
  693.                                 nullp += emdp->screensize;
  694.                         }
  695.                         if (fieldcount)
  696.                             /* we had some non-nulls & maybe some imbedded nulls */
  697.                             nullp++;
  698.                         if (nullp == smap_end)
  699.                             nullp = scr_map;
  700.  
  701.                         while (ptr != nullp) {
  702.                             /* now send the field */
  703.                             thechar = *ptr++;
  704.                             if (thechar == IBMNULL) {
  705.                                 if (emdp->nullsareblanks) {
  706.                                     /* put out a blank */
  707.                                     (*emdp->putchar)(0x40);
  708.                                 }
  709.                             }
  710.                             else {
  711.                                 /* translate character */
  712.                                 (*emdp->putchar)(asctoebc[thechar]);
  713.                             }
  714.                             if (ptr == mapend) 
  715.                                 ptr = scr_map;
  716.                         }
  717.                     }
  718.                     ptr = nextattp;
  719.                         /* next attr */
  720.                 }
  721.                 /* end if MDT set .. */
  722.                 else 
  723.                     ptr = look_attr(ptr, FWD);
  724.                     /* put us on attr */
  725.             }
  726.             while (ptr != endp);
  727.         }
  728.     }
  729.     (*emdp->putchar)(0xff);
  730.     (*emdp->putchar)(0xef);
  731.     (*emdp->putflush)();
  732.         /* telnet EOR */
  733.     return();
  734. }
  735.  
  736.  
  737. /*    this routine is called by cmd to process the 3270 command
  738.       erase all unprotected and by prompt to process the erase input key */
  739.  
  740. eau()
  741. {
  742.     register unsigned char * curp;
  743.     register unsigned char * eattp;
  744.     register unsigned char * mapend = smap_end;
  745.     unsigned char * endp;        /* original curp position for end test */
  746.     unsigned char * holdp;        /* original curp position for set_mod */
  747.  
  748.     curp = scr_map + emdp->screensize - 1;
  749.         /* start at end to wrap to top */
  750.     endp = curp = next_unp(FWD);
  751.         /* first position */
  752.  
  753.     if ((eattp = curp - 1) < scr_map) 
  754.         eattp += emdp->screensize;
  755.         /* attr. itself */
  756.  
  757.     if (*eattp < ATTR && !(*eattp & PROT)) {
  758.         /* if it really is an attr */
  759.         current_attr = eattp;
  760.         *eattp &= ~MDT;
  761.             /* turn off MDT */
  762.         holdp = curp;
  763.         while (*curp >= ATTR) {
  764.             /* null out the field */
  765.             *curp++ = IBMNULL;
  766.             if (curp == mapend) {
  767.                 set_mod(holdp, curp - holdp);
  768.                 holdp = curp = scr_map;
  769.             }
  770.         }
  771.         set_mod(holdp, curp - holdp);
  772.  
  773.         /* repeat until we have reached our original field */
  774.         while ((curp = next_unp(FWD)) != endp) {
  775.             if ((eattp = curp - 1) < scr_map) 
  776.                 eattp += emdp->screensize;
  777.             *eattp &= ~MDT;
  778.             for (holdp = curp; *curp >= ATTR; ) {
  779.                 /* null out the field */
  780.                 *curp++ = IBMNULL;
  781.                 if (curp == mapend) {
  782.                     set_mod(holdp, curp - holdp);
  783.                     holdp = curp = scr_map;
  784.                 }
  785.             }
  786.             set_mod(holdp, curp - holdp);
  787.         }
  788.     }
  789.     else {
  790.         /* no unprotected fields on screen */
  791.         cursor_ptr = scr_map;
  792.         newibmcursor();
  793.             /* follow the book */
  794.         current_attr = look_attr(scr_map, BACK);
  795.     }
  796. }
  797.  
  798.  
  799. ibm_make()
  800. {
  801.     short newsize = FALSE;
  802.     
  803.     if (emdp->scr_map != NULL)
  804.         /* already has IBM structures allocated ... */
  805.         return(0);
  806.     
  807.     switch (emdp->ibm_type) {
  808.         case IBMMOD2: {
  809.             emdp->linecount = COL_SIZE;        /* 24 */
  810.             emdp->linelength = ROW_SIZE;    /* 80 */
  811.             emdp->screensize = SCREEN_SIZE;
  812.             break;
  813.         }
  814.         case IBMMOD3: {
  815.             emdp->linecount = 32;
  816.             emdp->linelength = 80;
  817.             emdp->screensize = emdp->linecount * emdp->linelength;
  818.             newsize = TRUE;
  819.             break;
  820.         }
  821. #ifdef SUPPORTMOD4
  822.         /* emulator logic only handles <= 32 rows ... */
  823.         case IBMMOD4: {
  824.             emdp->linecount = 43;
  825.             emdp->linelength = 80;
  826.             emdp->screensize = emdp->linecount * emdp->linelength;
  827.             newsize = TRUE;
  828.             break;
  829.         }
  830. #endif
  831.         case IBMMOD5: {
  832.             emdp->linecount = 27;
  833.             emdp->linelength = 132;
  834.             emdp->screensize = emdp->linecount * emdp->linelength;
  835.             newsize = TRUE;
  836.             break;
  837.         }
  838.         default: {
  839.             emdp->linecount = COL_SIZE;
  840.             emdp->linelength = ROW_SIZE;
  841.             emdp->screensize = SCREEN_SIZE;
  842.             break;
  843.         }
  844.     }
  845.     emdp->lastcol = emdp->linelength - 1;
  846.     emdp->lastrow = emdp->linecount - 1;
  847.  
  848.     if (!memtest((long) emdp->screensize, "to make 3270 emulator")) {
  849.         return(-1);
  850.     }
  851.     
  852.     emdp->scr_map = malloc(emdp->screensize);                /* allocate the screen map */
  853.     if (emdp->scr_map == NULL) {
  854.         /* unlikely but conceivable */
  855.         return(-1);
  856.     }
  857.  
  858.     mem_clear(emdp->scr_map, emdp->screensize, (char) IBMNULL);
  859.  
  860.     if (emdp->color)
  861.         emdp->realattr = DSPMOD;
  862.     else
  863.         emdp->realattr = DSPD;
  864.     
  865.     emdp->cmdstate = CMNORM;
  866.     emdp->aid_key = AID_RESET;
  867.     
  868.     emdp->cursor_ptr = emdp->scr_map;                        /* current cursor position in screen map */
  869.     emdp->smap_end = emdp->scr_map + emdp->screensize;              /* end of map */
  870.  
  871.     emdp->ftsaveptr = &emdp->ftsavebuf[0];                    /* TODO dynamic? ptr into buffer */
  872.  
  873.     setcontext(emdp);            /* update globals */
  874.     
  875.     if (newsize)
  876.         setscreensize(emdp->fontsize);
  877.     
  878.     newibmcursor();
  879.     
  880.     return(0);
  881. }
  882.  
  883.  
  884. /* free memory used by the ibm emulator */
  885.  
  886. ibm_free(twp)
  887. struct winds * twp;
  888. {
  889.     if (twp->scr_map != NULL)
  890.         free(twp->scr_map);
  891.     twp->scr_map = NULL;
  892.  
  893.     ftrecovermem(twp);        /* free the file transfer memory */
  894. }
  895.  
  896.  
  897. ibm_init()
  898. {
  899.     /* initialize the command map */
  900.     commandmap[PT] = TRUE;
  901.     commandmap[GE] = TRUE;
  902.     commandmap[SBA] = TRUE;
  903.     commandmap[EUA] = TRUE;
  904.     commandmap[IC] = TRUE;
  905.     commandmap[SF] = TRUE;
  906.     commandmap[RA] = TRUE;
  907.     commandmap[SA] = TRUE;
  908.     commandmap[SFE] = TRUE;
  909.     commandmap[MF] = TRUE;
  910. }
  911.  
  912.  
  913.  
  914. ibm3270reset()
  915. {
  916.     emdp->cmdstate = CMNORM;
  917.     emdp->aid_key = AID_RESET;
  918.     emdp->current_attr = NULL;
  919.     emdp->cursor_ptr = emdp->scr_map;
  920.     emdp->scr_org = scr_map;
  921.  
  922.     emdp->xpos = 0;
  923.     emdp->ypos = 0;
  924.     
  925.     if (emdp->scr_map != NULL) {
  926.         mem_clear(emdp->scr_map, emdp->screensize, (char) IBMNULL);
  927.     }
  928.     
  929.     /* force an update */
  930.     setcontext(emdp);
  931.     newibmcursor();
  932.         /* manually update the winds struct */
  933.  
  934.     if (emdp->emwindow)
  935.         (*emdp->clear_scr)();
  936. }
  937.  
  938.  
  939. /*
  940.     return the current attribute 
  941. */
  942.  
  943. pc_attr()
  944. {
  945.     unsigned char temp;
  946.  
  947.     if (current_attr != NULL) 
  948.         temp = *current_attr;
  949.     else
  950.         temp = 0;
  951.     return(temp);
  952. }
  953.  
  954.  
  955. /*
  956.     look forward or back thru screen map for attribute byte;
  957.     skips *ptr 
  958. */
  959.  
  960. unsigned char *look_attr (ptr, direction)
  961. register unsigned char *ptr; 
  962. char direction;
  963. {
  964.     register unsigned char * breakp;
  965.     register unsigned char isattr = ATTR;
  966.     unsigned char * tempp;
  967.  
  968.     tempp = ptr;
  969.     if (direction == FWD) {
  970.         ptr++;
  971.         /* break on end of screen */
  972.         breakp = smap_end;
  973.         while (ptr < breakp) {
  974.             if ( (*ptr++ < isattr) ) 
  975.                 return(ptr - 1);
  976.         }
  977.         /* now break on original ptr pos */
  978.         breakp = tempp;
  979.         ptr = scr_map;
  980.         while (ptr <= breakp) {
  981.             if ( (*ptr++ < isattr) ) 
  982.                 return(ptr - 1);
  983.         }
  984.     }
  985.     else {
  986.         /* as above */
  987.         breakp = scr_map;
  988.         while (--ptr >= breakp) {
  989.             if ( (*ptr < isattr) ) 
  990.                 return(ptr);
  991.         }
  992.         breakp = tempp;
  993.         ptr = smap_end;
  994.         while (--ptr >= breakp) {
  995.             if ( (*ptr < isattr) ) 
  996.                 return(ptr);
  997.         }
  998.     }
  999.     return(NULL);
  1000.         /* no luck */
  1001. }
  1002.  
  1003.  
  1004. /*
  1005.     returns the attribute in force for this point
  1006. */
  1007.  
  1008. ibm_attr(ptr)
  1009. register unsigned char *ptr; 
  1010. {
  1011.     register unsigned char * breakp;
  1012.     register unsigned char isattr = ATTR;
  1013.     unsigned char * tempp;
  1014.  
  1015.     ptr++;                /* correct to adapt look_attr code: check *ptr TOO! */
  1016.     tempp = ptr;
  1017.  
  1018.     /* as above */
  1019.     breakp = scr_map;
  1020.     while (--ptr >= breakp) {
  1021.         if ( (*ptr < isattr) ) 
  1022.             return(*ptr);
  1023.     }
  1024.     breakp = tempp;
  1025.     ptr = smap_end;
  1026.     while (--ptr >= breakp) {
  1027.         if ( (*ptr < isattr) ) 
  1028.             return(*ptr);
  1029.     }
  1030.  
  1031.     return(0);
  1032.         /* no attribute in force... */
  1033. }
  1034.  
  1035.  
  1036. /*
  1037. *****  find the byte following the next unprotected field
  1038. */
  1039.  
  1040. unsigned char *next_unp (direction)
  1041. char direction;
  1042. {
  1043.     register unsigned char *ptr;
  1044.     register unsigned char *nextp;
  1045.     register unsigned char *endp;
  1046.  
  1047.     ptr = cursor_ptr;
  1048.  
  1049.     if (direction == FWD) {
  1050.         if ((nextp = ptr + 1) == smap_end) 
  1051.             nextp = scr_map; 
  1052.         if (*ptr < ATTR && !(*ptr & PROT) && *nextp >= ATTR) 
  1053.             return(nextp);
  1054.     }
  1055.     else 
  1056.         if (--ptr < scr_map) 
  1057.             ptr += emdp->screensize;
  1058.  
  1059.     if ((endp = ptr = look_attr(ptr, direction)) != NULL) {
  1060.         while (TRUE) {
  1061.             if ((*ptr & PROT) == FALSE) {
  1062.                 if ((nextp = ptr + 1) == smap_end) 
  1063.                     nextp = scr_map; 
  1064.                 if (*nextp >= ATTR) 
  1065.                     /* it's data, and not just another attribute */
  1066.                     return(nextp);
  1067.             }
  1068.             if ((ptr = look_attr(ptr, direction)) == endp) 
  1069.                 break;
  1070.         }
  1071.     }
  1072.     return(cursor_ptr);
  1073. }
  1074.  
  1075.  
  1076. /*
  1077. *****     return pointer to byte following the next unprotected field,
  1078. *****    if wrap occurs return scr_map
  1079. */
  1080.  
  1081. unsigned char *first_unp(start)
  1082. char * start;
  1083. {
  1084.     register unsigned char *ptr;
  1085.     register unsigned char *nextp;
  1086.     register unsigned char *startp;
  1087.  
  1088.     ptr = startp = start;
  1089.  
  1090.     if ((*ptr < ATTR) && !(*ptr & PROT)) {
  1091.         /* kevin -- test to verify first character not a field dropped */
  1092.         if ((nextp = ptr + 1) == smap_end) 
  1093.             nextp = scr_map; 
  1094.         return(nextp);
  1095.     }
  1096.  
  1097.     while ((ptr = look_attr(ptr, FWD)) != NULL) {
  1098.         if (ptr < startp)
  1099.             return(scr_map);
  1100.             /* if we've wrapped around, we set the pointer to buffer addr 0 */
  1101.             
  1102.         if ((*ptr & PROT) == FALSE) {
  1103.             if ((nextp = ptr + 1) == smap_end) 
  1104.                 nextp = scr_map; 
  1105.             return(nextp); 
  1106.  
  1107.         /* it's data, and not just another attribute
  1108.         Apparently we should not be testing this -- PT problem w/ XA
  1109.         
  1110.             if (*nextp >= ATTR) 
  1111.                 return(nextp); 
  1112.         */
  1113.         }
  1114.     }
  1115.     return(scr_map);
  1116. }
  1117.  
  1118.  
  1119. /*
  1120. ****  generate 12 bit buffer address with appropriate IBM coding
  1121.  */
  1122.  
  1123. int addr_12(convarg)
  1124. int convarg;
  1125. {
  1126.     register unsigned char achar;
  1127.     unsigned int x;
  1128.  
  1129.     achar = convarg / 64;
  1130.     achar |= 0x40;
  1131.     if ((achar & 0x0f) <= 9) {
  1132.         if ((achar & 0x30) == 0x30 
  1133.                 || (achar & 0x0f) >= 2 
  1134.                 || achar == 0x41 
  1135.                 || achar == 0x51
  1136.             )
  1137.             achar |= 0x80;
  1138.     }
  1139.     x = achar << 8;
  1140.     achar = convarg % 64;
  1141.     achar |= 0x40;
  1142.     if ((achar & 0x0f) <= 9) {
  1143.         if ((achar & 0x30) == 0x30 
  1144.                 || (achar & 0x0f) >= 2 
  1145.                 || achar == 0x41 
  1146.                 || achar == 0x51
  1147.             )
  1148.             achar |= 0x80;
  1149.     }
  1150.     x |= achar;
  1151.     return(x);
  1152. }
  1153.  
  1154. /*
  1155. *****  clear an area of memory
  1156. */
  1157.  
  1158.  
  1159. mem_clear(clearptr, len, value)
  1160. register char * clearptr;
  1161. register int  len;
  1162. register char value;
  1163. {
  1164.     register char * endptr;
  1165.  
  1166.     for (endptr = clearptr + len; clearptr < endptr; )
  1167.         *clearptr++ = value;
  1168. }
  1169.  
  1170.  
  1171. /* test a 3270 character stream to ascertain whether a DOWNLOAD is
  1172.     being requested
  1173.     
  1174.     check fmt:
  1175.     0     1     2     3     4     5     6     7
  1176.     | SBA |  ?  |  ?  | SBA |  ?  |  ?  | 1B  | 1B
  1177.     
  1178.     Presumably duplicate SBA's are a rare occurrence.
  1179. */
  1180.  
  1181. ft_check(ptr, length)
  1182. register char *ptr;
  1183. register int  length;
  1184. {
  1185. /*
  1186.     if (length != 79)
  1187.         return(length);
  1188. */
  1189.     if (*ptr != 0x11 && *(ptr + 3) != 0x11) 
  1190.         return (length);
  1191.     if (*(ptr + 6) != 0x1b && *(ptr + 7) != 0x1b) 
  1192.         return(length);
  1193.  
  1194.     emdp->event_reg |= TFTP_ON;
  1195.     msetsendm(FALSE);                             /* turn off send menu items */
  1196.  
  1197.     emdp->event_reg |= LINE_25;
  1198.     ft_header();
  1199.     (*emdp->putchar)(0xfd);
  1200.     (*emdp->putchar)(ftinit ( (int) *(ptr+8), 0));        /* version number */
  1201.     (*emdp->putchar)(0x00);                                /* zero indicates running tn */
  1202.     ft_trailer();
  1203.     return (0);
  1204. }
  1205.  
  1206.  
  1207.  
  1208. /* set modflg to reflect changed lines */
  1209.  
  1210. set_mod(pmod, ccount)
  1211. unsigned char * pmod;            /* -> first position changed in map */
  1212. register int ccount;            /* # of characters changed */
  1213. {
  1214.     register int line;
  1215.     register int count;
  1216.  
  1217.     if (modflg >= SCRALLMOD)
  1218.         /* the whole thing's been set already */
  1219.         return;
  1220.         
  1221.     line = (pmod - scr_map) / emdp->linelength;                        /* y pos */
  1222.     count = pmod - (scr_map + line * emdp->linelength);            /* x pos */
  1223.     
  1224.     ccount += count;
  1225.         /* add xpos to ccount so end will come out right */
  1226.         
  1227.     for (count = 0; count < ccount; count += emdp->linelength) {
  1228.         modflg |= modmask[line];
  1229.         if (++line >= emdp->linecount)
  1230.             /* wrap around if necessary */
  1231.             line = 0;
  1232.     }
  1233. }
  1234.  
  1235.  
  1236.  
  1237.